package com.question.common.utils;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.question.common.model.dto.DynamicFieldDTO;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.FieldAccessor;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 运行时动态修改类结构
 *
 * @author star
 * @since 2023/9/11
 */
public class DynamicClassUtil {

    /**
     * 动态新增属性和值
     *
     * @param source 源对象
     * @param fields 字段集合
     * @return Object
     * @throws Exception
     */
    public static Object dynamicField(Object source, List<DynamicFieldDTO> fields) throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        // 创建一个ByteBuddy代理类
        DynamicType.Builder<?> builder = new ByteBuddy()
                .subclass(source.getClass());

        // 从Map中获取字段名和初始值，然后定义字段和初始值
        for (DynamicFieldDTO field : fields) {
            String fieldName = field.getTargetFieldName();

            // 定义字段
            builder = builder.defineField(fieldName, String.class, Visibility.PRIVATE);

            // 定义set方法
            String setMethodName = "set" + capitalize(fieldName);
            builder = builder.defineMethod(setMethodName, void.class, Visibility.PUBLIC)
                    .withParameter(String.class)
                    .intercept(FieldAccessor.ofBeanProperty());

            // 定义get方法
            String getMethodName = "get" + capitalize(fieldName);
            builder = builder.defineMethod(getMethodName, String.class, Visibility.PUBLIC)
                    .intercept(FieldAccessor.ofBeanProperty());
        }

        // 创建类并实例化对象
        Class<?> dynamicType = builder.make()
                .load(source.getClass().getClassLoader())
                .getLoaded();
        Object target = dynamicType.newInstance();
        BeanUtils.copyProperties(source, target);
        // 调用set方法设置字段的值
        for (DynamicFieldDTO field : fields) {
            String fieldName = field.getTargetFieldName();
            String fieldValue = field.getTargetFieldValue();
            if (StringUtils.isNotBlank(fieldValue)) {
                String setMethodName = "set" + capitalize(fieldName);
                Method setMethod = dynamicType.getMethod(setMethodName, fieldValue.getClass());
                setMethod.invoke(target, fieldValue);
            }
        }

        return target;
    }

    /**
     * 首字母转大写
     *
     * @param str 数据
     * @return String
     */
    private static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

}
